package com.yjz.jvm.反射.jdk7方法句柄;

import lombok.SneakyThrows;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class User {
    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public void speck(String msg) {
        System.out.println(name + "在说:" + msg);
    }

    private void sing() {
        System.out.println(name + "在私有方法里唱歌");
    }

    //提供一个public方法,暴露私有方法的句柄,这样外面就能获取私有方法句柄了
    @SneakyThrows
    public MethodHandle getSingMethodHandle() {
        return MethodHandles.lookup().findVirtual(this.getClass(), "sing", MethodType.methodType(void.class));
    }


    @SneakyThrows
    public static void main(String[] args) {
        User user = new User("张三");

        //构造Lookup
        MethodHandles.Lookup lookup = MethodHandles.lookup();

        //Lookup查找方法句柄
        MethodHandle speckMethodHandle = lookup.findVirtual(User.class, "speck", MethodType.methodType(void.class, String.class));

        //用句柄调方法,类似于method
        speckMethodHandle.invokeExact(user, "今天天气不错");

        //若不在同一个类里面此处会报错,因为没有访问权限
        //详见:https://www.v2ex.com/t/671606#reply8
        MethodHandle singMethodHandle = lookup.findSpecial(User.class, "sing", MethodType.methodType(void.class), User.class);

        singMethodHandle.invokeExact(user);
    }
}
